package com.dxl.handler;

import com.dxl.utils.ResDataUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.UnexpectedTypeException;
import javax.validation.ValidationException;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;

/**
 * @author dxl
 * @date 2020/11/14 23:20
 */
@ControllerAdvice //作为全局异常处理的切面类
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 请求方式不支持 有效
     */
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    @ResponseBody
    public Object handleException(HttpRequestMethodNotSupportedException e) {
        log.error(e.getMessage(), e);
        return ResDataUtil.failure("不支持' " + e.getMethod() + "'请求");
    }
    /**
     * 校验异常 处理Get请求中 使用@Valid 验证路径中请求实体校验失败后抛出的异常
     */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public Object BindException(BindException e) {
        return ResDataUtil.failure(e.getBindingResult().getFieldError().getDefaultMessage());
    }
    /**
     * 校验异常 处理请求参数格式错误 @RequestBody上validate失败后抛出的异常
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public Object exceptionHandler(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        String errorMesssage = "";
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            errorMesssage += fieldError.getDefaultMessage();
        }
        log.error(errorMesssage, e);
        return ResDataUtil.failure(e.getBindingResult().getFieldError().getDefaultMessage());
    }
    /**
     * 校验异常 处理请求参数格式错误 @RequestParam上validate失败后抛出的异常 [没效果？]
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    @ResponseBody
    public Object ConstraintViolationExceptionHandler(ConstraintViolationException e) {
        log.info("validationException: " + e.getMessage());
        String message = e.getConstraintViolations()
                .stream()
                .map(ConstraintViolation::getMessage)
                .findFirst()
                .orElse("Optional.empty");
        return ResDataUtil.failure(message);
    }
    /**
     * 校验异常
     */
    @ExceptionHandler(value = ValidationException.class)
    @ResponseBody
    public Object validationException(ValidationException e) {
        log.info("validationException: " + e.getMessage());
        return ResDataUtil.failure(e.getMessage());
    }

    /**
     * 参数校验注解错误抛出的异常
     */
    @ExceptionHandler(UnexpectedTypeException.class)
    @ResponseBody
    public Object handleMethodArgumentNotValidException(UnexpectedTypeException e) {
        log.error(e.getMessage(), e);
        return ResDataUtil.failure("检验参数注解错误");
    }
    /**
     * sql异常
     */
    @ExceptionHandler(SQLException.class)
    @ResponseBody
    public Object sqlExceptionHandle(SQLException e) {
        log.error(e.getMessage(), e);
        return ResDataUtil.failure("401",e.getMessage());
    }
    /**
     * sql异常 有效
     */
    @ExceptionHandler(DataAccessException.class)
    @ResponseBody
    public Object sql1ExceptionHandle(SQLIntegrityConstraintViolationException e) {
        log.error(e.getMessage(), e);
        return ResDataUtil.failure("402",e.getMessage());
    }
    /**
     * 运行时异常 有效
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public Object runtimeException(RuntimeException e) {
        log.error(e.getMessage(), e);
        return ResDataUtil.failure("400",e.getMessage());
    }
//    /**
//     * 系统异常
//     */
//    @ExceptionHandler(Exception.class)
//    @ResponseBody
//    public Object exception(Exception e) {
//        log.error(e.getMessage(), e);
//        return ResDataUtil.failure(ResultEnums.INTERNAL_SERVER_ERROR,e.getMessage());
//    }
}